home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / Histogram.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  7.5 KB  |  316 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <string.h>
  19. #include <windows.h>
  20.  
  21. #include "VBitmap.h"
  22. #include "Histogram.h"
  23. #include "Error.h"
  24.  
  25. const char histo_log_table[]={
  26. 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  27. 8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,
  28. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  29. 7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  30. 6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,
  31. 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  32. 5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,
  33. 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  34. 4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,
  35. 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  36. 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,
  37. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  38. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  39. 2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
  40. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  41. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  42. };
  43.  
  44. const RGBQUAD Histogram::fore_colors[]={
  45.     { 0xff, 0x00, 0x00 },
  46.     { 0x00, 0xff, 0x00 },
  47.     { 0x00, 0x00, 0xff },
  48.     { 0xff, 0xff, 0xff },
  49. };
  50.  
  51. Histogram::Histogram(HDC hDC, int max_height) {
  52.     struct {
  53.         BITMAPINFO bmi;
  54.         RGBQUAD bmiColor1;
  55.     } bmp;
  56.  
  57.     hBitmapGraph = NULL;
  58.     hDCGraph = NULL;
  59.  
  60.     bmp.bmi.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
  61.     bmp.bmi.bmiHeader.biWidth            = 256;
  62.     bmp.bmi.bmiHeader.biHeight            = max_height;
  63.     bmp.bmi.bmiHeader.biPlanes            = 1;
  64.     bmp.bmi.bmiHeader.biBitCount        = 1;
  65.     bmp.bmi.bmiHeader.biCompression        = BI_RGB;
  66.     bmp.bmi.bmiHeader.biSizeImage        = max_height * 32;
  67.     bmp.bmi.bmiHeader.biXPelsPerMeter    = 80;
  68.     bmp.bmi.bmiHeader.biYPelsPerMeter    = 72;
  69.     bmp.bmi.bmiHeader.biClrUsed            = 2;
  70.     bmp.bmi.bmiHeader.biClrImportant    = 2;
  71.     bmp.bmi.bmiColors[0].rgbBlue = 0;
  72.     bmp.bmi.bmiColors[0].rgbGreen = 0;
  73.     bmp.bmi.bmiColors[0].rgbRed = 0;
  74.     bmp.bmiColor1.rgbBlue = 0;
  75.     bmp.bmiColor1.rgbGreen = 0;
  76.     bmp.bmiColor1.rgbRed = 0xff;
  77.  
  78.     if (!(hDCGraph = CreateCompatibleDC(hDC)))
  79.         throw MyError("Histogram: Couldn't create display context");
  80.  
  81.     if (!(hBitmapGraph = CreateDIBSection(hDC, &bmp.bmi, DIB_RGB_COLORS, (LPVOID *)&lpGraphBits, NULL, 0)))
  82.         throw MyError("Histogram: Couldn't allocate DIB section");
  83.  
  84.     SelectObject(hDCGraph, hBitmapGraph);
  85.  
  86.     this->max_height = max_height;
  87.  
  88.     SetMode(MODE_GRAY);
  89. }
  90.  
  91. Histogram::~Histogram() {
  92.     if (hBitmapGraph) DeleteObject(hBitmapGraph);
  93.     if (hDCGraph) DeleteDC(hDCGraph);
  94. }
  95.  
  96. void Histogram::Zero() {
  97.     memset(histo, 0, sizeof histo);
  98.     total_pixels = 0;
  99. }
  100.  
  101. void Histogram::Process(const VBitmap *vbmp) {
  102. #if 0
  103.     Pixel c, *src = (Pixel *)vbmp->data;
  104.     long w, h;
  105.  
  106.     if (!vbmp->width || !vbmp->height) return;
  107.  
  108.     h = vbmp->height; 
  109.     do {
  110.         w = vbmp->width;
  111.         do {
  112.             c = *src++;
  113.             ++histo[(54*((c>>16)&255) + 183*((c>>8)&255) + 19*(c&255))>>8];
  114.         } while(--w);
  115.  
  116.         src = (Pixel *)((char *)src + vbmp->modulo);
  117.     } while(--h);
  118. #else
  119.  
  120.     if (histo_mode < MODE_GRAY)
  121.         asm_histogram_color_run((char *)vbmp->data + histo_mode, vbmp->w, vbmp->h, vbmp->pitch, histo);
  122.     else
  123.         asm_histogram_gray_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo);
  124.  
  125. #endif
  126.  
  127.     total_pixels += vbmp->w * vbmp->h;
  128. }
  129.  
  130. void Histogram::Process24(const VBitmap *vbmp) {
  131. #if 0
  132.     Pixel c, *src = (Pixel *)vbmp->data;
  133.     long w, h;
  134.  
  135.     if (!vbmp->w || !vbmp->h) return;
  136.  
  137.     h = vbmp->h; 
  138.     do {
  139.         w = vbmp->w;
  140.         do {
  141.             c = *src++;
  142.             ++histo[(54*((c>>16)&255) + 183*((c>>8)&255) + 19*(c&255))>>8];
  143.         } while(--w);
  144.  
  145.         src = (Pixel *)((char *)src + vbmp->modulo);
  146.     } while(--h);
  147. #else
  148.  
  149.     if (histo_mode < MODE_GRAY)
  150.         asm_histogram_color24_run((char *)vbmp->data + histo_mode, vbmp->w, vbmp->h, vbmp->pitch, histo);
  151.     else
  152.         asm_histogram_gray24_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo);
  153.  
  154. #endif
  155.  
  156.     total_pixels += vbmp->w * vbmp->h;
  157. }
  158.  
  159. void Histogram::Process16(const VBitmap *vbmp) {
  160.     static const long pixmasks[3]={
  161.         0x001f,
  162.         0x03e0,
  163.         0x7c00,
  164.     };
  165.  
  166.     if (histo_mode < MODE_GRAY)
  167.         asm_histogram16_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo, pixmasks[histo_mode]);
  168.     else
  169.         asm_histogram16_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo, 0x7fff);
  170.  
  171.     total_pixels += vbmp->w * vbmp->h;
  172. }
  173.  
  174. void Histogram::ComputeHeights(long *heights, long graph_height) {
  175. #if 0
  176.     long h;
  177.     double c = log(pow(2, 1.0/8.0));
  178.  
  179.     for(int i=0; i<256; i++) {
  180.         if (!histo[i])
  181.             heights[i] = 0;
  182.         else {
  183.             h = graph_height + log((double)histo[i]/total_pixels) / c;
  184.  
  185.             if (h<0)
  186.                 heights[i] = 1;
  187.             else
  188.                 heights[i] = h;
  189.         }
  190.  
  191. //            heights[i] = (histo[i]*graph_height + total_pixels - 1) / total_pixels;
  192.     }
  193. #else
  194.     long h;
  195.     int s;
  196.  
  197.     for(int i=0; i<256; i++) {
  198.         if (!histo[i])
  199.             heights[i] = 0;
  200.         else {
  201.             if (histo[i] == total_pixels)
  202.                 heights[i] = graph_height;
  203.             else {
  204.                 h = MulDiv(histo[i], 0x10000000L, total_pixels);
  205.  
  206.                 if (!h)
  207.                     heights[i] = 1;
  208.                 else {
  209.                     s = -1;
  210.  
  211.                     while(h<0x10000000) {
  212.                         h<<=1;
  213.                         ++s;
  214.                     }
  215.  
  216.                     h = graph_height - 8*s - histo_log_table[(h>>20) & 255];
  217.                     if (h<1) h=1;
  218.  
  219.                     heights[i] = h;
  220.                 }
  221.             }
  222.  
  223.         }
  224.  
  225. //            heights[i] = (histo[i]*graph_height + total_pixels - 1) / total_pixels;
  226.     }
  227. #endif
  228. }
  229.  
  230. void Histogram::Draw(HDC hDC, LPRECT lpr) {
  231.     long heights[256];
  232.  
  233. #if 1
  234.     int i,j;
  235.  
  236.     ComputeHeights(heights, lpr->bottom - lpr->top);
  237.  
  238.     GdiFlush();
  239.  
  240.     memset(lpGraphBits, 0, 32*(lpr->bottom - lpr->top));
  241.  
  242.     for(i=0; i<256; i++) {
  243.         char *lp = lpGraphBits + (i>>3);
  244.         char mask = 0x80 >> (i&7);
  245.  
  246.         j = heights[i];
  247.         if(j) do {
  248.             *lp |= mask;
  249.             lp += 32;
  250.         } while(--j);
  251.     }
  252.  
  253.     BitBlt(hDC, lpr->left,lpr->top, 256, lpr->bottom-lpr->top, hDCGraph, 0, 0, SRCCOPY);
  254. #else
  255.     long frac_accum, frac_inc;
  256.     long width = lpr->right - lpr->left;
  257.     long height = lpr->bottom - lpr->top;
  258.     HPEN hPenOld, hPenPositive, hPenNegative;
  259.     int i;
  260.  
  261.     frac_inc = width<256 ? 0xFFFFFF/(width-1) : (0x1000000+width/2)/width;
  262.  
  263.     ComputeHeights(heights, height);
  264.  
  265.     hPenPositive = CreatePen(PS_SOLID, 0, RGB(255,0,0));
  266.     hPenNegative = CreatePen(PS_SOLID, 0, RGB(0,0,0));
  267.  
  268.     if (hPenPositive && hPenNegative) {
  269.         hPenOld = SelectObject(hDC, hPenNegative);
  270.  
  271.         frac_accum = 0;
  272.  
  273.         for(i=0; i<width; i++) {
  274.             if (heights[frac_accum>>16]<height) {
  275.                 MoveToEx(hDC, lpr->left+i, lpr->top, NULL);
  276.                 LineTo(hDC, lpr->left+i, lpr->top+(height-heights[frac_accum>>16]));
  277.             }
  278.  
  279.             frac_accum += frac_inc;
  280.         }
  281.  
  282.         SelectObject(hDC, hPenPositive);
  283.  
  284.         frac_accum = 0;
  285.  
  286.         for(i=0; i<width; i++) {
  287.             if (heights[frac_accum>>16]) {
  288.                 MoveToEx(hDC, lpr->left+i, lpr->top+(height-heights[frac_accum>>16]), NULL);
  289.                 LineTo(hDC, lpr->left+i, lpr->bottom);
  290.             }
  291.  
  292.             frac_accum += frac_inc;
  293.         }
  294.  
  295.         SelectObject(hDC, hPenOld);
  296.     }
  297.  
  298.     if (hPenPositive) DeleteObject(hPenPositive);
  299.     if (hPenNegative) DeleteObject(hPenNegative);
  300. #endif
  301. }
  302.  
  303. void Histogram::SetMode(int new_mode) {
  304.     if (new_mode == MODE_NEXT) {
  305.         if (++histo_mode >= NUM_MODES) histo_mode = 0;
  306.     } else
  307.         histo_mode = new_mode;
  308.  
  309.     SetDIBColorTable(hDCGraph, 1, 1, &fore_colors[histo_mode]);
  310.  
  311. }
  312.  
  313. int Histogram::GetMode() {
  314.     return histo_mode;
  315. }
  316.